﻿using Newtonsoft.Json;
using RMS.Common;
using RMS.EF.Model.Common;
using RMS.EF.Model.Log;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

namespace RMS.BLL
{
    /// <summary>
    /// 捕捉错误信息记录到MongoDB并按照接口Json格式返回错误信息
    /// </summary>
    public class ErrorAttribute : ActionFilterAttribute, IExceptionFilter
    {
        /// <summary>
        /// 异常
        /// </summary>
        /// <param name="filterContext"></param>
        public void OnException(ExceptionContext filterContext)
        {
            var result = new CommonOutPutVm();
            NLogHelper nlog = new NLogHelper();
            #region 获取异常信息，入库保存
            try
            {
                #region 日志信息生成
                Exception Error = filterContext.Exception;
                ErrorLog log = new ErrorLog();
                log.ProjectName = ConfigurationManager.AppSettings["AppName"] ?? "Null";
                log.Error = JsonConvert.SerializeObject(Error);
                log.Message = Error.Message;
                log.Url = HttpContext.Current.Request.Url == null ? string.Empty : HttpContext.Current.Request.Url.ToString();//错误发生地址
                log.UrlReferrer = HttpContext.Current.Request.UrlReferrer == null ? string.Empty : HttpContext.Current.Request.UrlReferrer.ToString();//来源链接
                log.UrlContentType = HttpContext.Current.Request.ContentType;
                #region 访问参数
                if (log.UrlContentType == "application/json")
                {
                    HttpContext.Current.Request.InputStream.Position = 0;
                    StreamReader sr = new StreamReader(HttpContext.Current.Request.InputStream);
                    log.UrlParameter = sr.ReadToEnd();
                }
                else
                {
                    log.UrlParameter = HttpContext.Current.Request.Form.ToString();
                }
                #endregion
                #region 客户端IP地址
                if (!string.IsNullOrWhiteSpace(HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]))
                    log.ClientIP = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
                else
                    log.ClientIP = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
                if (string.IsNullOrWhiteSpace(log.ClientIP))
                    log.ClientIP = HttpContext.Current.Request.UserHostAddress;
                #endregion
                #endregion
                var logtype = ConfigurationManager.AppSettings["LogType"];
                switch (logtype)
                {
                    case "MongoDB":
                        MongoDBHelper.InsertOne<ErrorLog>(log);
                        result.Message = GetRealExceptionMsg(Error);
                        break;
                    default:
                        nlog.Error("ERRORLOG:" + JsonConvert.SerializeObject(log));
                        break;
                }
            }
            #endregion
            #region 日志记录异常处理
            catch (Exception e)
            {
                result.Message = "异常处理错误：" + filterContext.Exception.Message;
                try
                {
                    nlog.Fatal(JsonConvert.SerializeObject(e));
                    var url = HttpContext.Current.Request.Url == null ? string.Empty : HttpContext.Current.Request.Url.ToString();//错误发生地址
                    var urlReferrer = HttpContext.Current.Request.UrlReferrer == null ? string.Empty : HttpContext.Current.Request.UrlReferrer.ToString();//来源链接
                    var urlContentType = HttpContext.Current.Request.ContentType;
                    nlog.Error("ERROR:\r\nUrl:" + url + "\r\nUrlReferrer" + urlReferrer + "\r\nContentType:" + urlContentType);
                    if (urlContentType == "application/json")
                    {
                        HttpContext.Current.Request.InputStream.Position = 0;
                        StreamReader sr = new StreamReader(HttpContext.Current.Request.InputStream);
                        nlog.Error(sr.ReadToEnd());
                    }
                    else
                    {
                        nlog.Error(HttpContext.Current.Request.Form.ToString());
                    }
                    nlog.Error(filterContext.Exception);
                }
                catch (Exception)
                {
                }
            }
            #endregion
            #region 返回错误信息对象输出错误信息
            finally
            {
                var request = filterContext.HttpContext.Request;
                #region POST
                if (request.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase))
                {
                    JsonResult json = new JsonResult();
                    json.Data = result;
                    json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
                    filterContext.Result = json;//返回错误信息
                }
                #endregion
                #region GET
                else if (request.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase))
                {
                    filterContext.Result = new RedirectResult("~/Error/Index?msg=" + result.Message.UrlEncode());
                }
                #endregion
                #region 其他
                else
                {
                    filterContext.Result = new HttpUnauthorizedResult();
                }
                #endregion
                filterContext.ExceptionHandled = true;
                filterContext.HttpContext.Response.StatusCode = 200;
            }
            #endregion
        }
        /// <summary>
        /// 获取最内层异常提示
        /// </summary>
        /// <param name="error"></param>
        /// <returns></returns>
        private string GetRealExceptionMsg(Exception error)
        {
            if (error == null)
            {
                return string.Empty;
            }
            if (error.InnerException == null)
            {
                return error.Message;
            }
            return GetRealExceptionMsg(error.InnerException);
        }

    }
}
